package com.design.cfr;

import com.design.cfr.model.ChainResponsibilityElementResult;
import com.design.cfr.model.ChainResponsibilityResult;
import lombok.extern.slf4j.Slf4j;

import java.util.function.Function;

/**
 * Normal chain responsibility abstract
 *
 * @description: 通用责任连，执行方式为链式执行
 * T --> apply(T t)的参数
 * @author: cyj
 * @date 2022 -08-12 15:38:51
 */
@Slf4j
public abstract class NormalChainResponsibilityAbstract<T>
        extends ChainResponsibility<T, ChainResponsibilityElementResult, ChainResponsibilityResult> {

    @Override
    public ChainResponsibilityResult start(T t) {
        return startCommon(t, (ChainResponsibility<T, ChainResponsibilityElementResult, ChainResponsibilityResult> element) -> element.apply(t));
    }

    @Override
    public ChainResponsibilityResult startNothrow(T t){
        return startCommon(t, (ChainResponsibility<T, ChainResponsibilityElementResult, ChainResponsibilityResult> element) -> {
            ChainResponsibilityElementResult apply;
            try {
                apply = element.apply(t);
            } catch (Exception e) {
                log.warn("执行责任链异常!", e);
                apply = ChainResponsibilityElementResult.builder()
                        .pass(false)
                        .aClass(element.getClass())
                        .message(e.getMessage())
                        .build();
            }
            return apply;
        });
    }

    private ChainResponsibilityResult startCommon(T t,
                                                  Function<ChainResponsibility<T, ChainResponsibilityElementResult, ChainResponsibilityResult>,
                                                          ChainResponsibilityElementResult> resultSupplier) {
        // new结果对象
        ChainResponsibilityResult chainResponsibilityResult = new ChainResponsibilityResult();
        ChainResponsibility<T, ChainResponsibilityElementResult, ChainResponsibilityResult> element = this;
        // 链式执行
        do {
            chainResponsibilityResult.getApplyResultElements().add(resultSupplier.apply(element));
            element= element.getNext();
        } while (null != element);

        // 设置结果
        chainResponsibilityResult.setResult();
        return chainResponsibilityResult;
    }
}
